1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.builder;
18  
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.List;
22  
23  import org.apache.commons.lang3.ArrayUtils;
24  
25  /**
26   * <p>
27   * Assists in implementing {@link Diffable#diff(Object)} methods.
28   * </p>
29   * 
30   * <p>
31   * To use this class, write code as follows:
32   * </p>
33   * 
34   * <pre>
35   * public class Person implements Diffable&lt;Person&gt; {
36   *   String name;
37   *   int age;
38   *   boolean smoker;
39   *   
40   *   ...
41   *   
42   *   public DiffResult diff(Person obj) {
43   *     // No need for null check, as NullPointerException correct if obj is null
44   *     return new DiffBuilder(this, obj, ToStringStyle.SHORT_PREFIX_STYLE)
45   *       .append("name", this.name, obj.name)
46   *       .append("age", this.age, obj.age)
47   *       .append("smoker", this.smoker, obj.smoker)
48   *       .build();
49   *   }
50   * }
51   * </pre>
52   * 
53   * <p>
54   * The {@code ToStringStyle} passed to the constructor is embedded in the
55   * returned {@code DiffResult} and influences the style of the
56   * {@code DiffResult.toString()} method. This style choice can be overridden by
57   * calling {@link DiffResult#toString(ToStringStyle)}.
58   * </p>
59   * 
60   * @since 3.3
61   * @version $Id$
62   * @see Diffable
63   * @see Diff
64   * @see DiffResult
65   * @see ToStringStyle
66   */
67  public class DiffBuilder implements Builder<DiffResult> {
68  
69      private final List<Diff<?>> diffs;
70      private final boolean objectsTriviallyEqual;
71      private final Object left;
72      private final Object right;
73      private final ToStringStyle style;
74  
75      /**
76       * <p>
77       * Constructs a builder for the specified objects with the specified style.
78       * </p>
79       * 
80       * <p>
81       * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will
82       * not evaluate any calls to {@code append(...)} and will return an empty
83       * {@link DiffResult} when {@link #build()} is executed.
84       * </p>
85       * 
86       * @param lhs
87       *            {@code this} object
88       * @param rhs
89       *            the object to diff against
90       * @param style
91       *            the style will use when outputting the objects, {@code null}
92       *            uses the default
93       * @param testTriviallyEqual
94       *            If true, this will test if lhs and rhs are the same or equal.
95       *            All of the append(fieldName, lhs, rhs) methods will abort
96       *            without creating a field {@link Diff} if the trivially equal
97       *            test is enabled and returns true.  The result of this test
98       *            is never changed throughout the life of this {@link DiffBuilder}.
99       * @throws IllegalArgumentException
100      *             if {@code lhs} or {@code rhs} is {@code null}
101      * @since 3.4
102      */
103     public DiffBuilder(final Object lhs, final Object rhs,
104             final ToStringStyle style, final boolean testTriviallyEqual) {
105 
106         if (lhs == null) {
107             throw new IllegalArgumentException("lhs cannot be null");
108         }
109         if (rhs == null) {
110             throw new IllegalArgumentException("rhs cannot be null");
111         }
112 
113         this.diffs = new ArrayList<Diff<?>>();
114         this.left = lhs;
115         this.right = rhs;
116         this.style = style;
117 
118         // Don't compare any fields if objects equal
119         this.objectsTriviallyEqual = testTriviallyEqual && (lhs == rhs || lhs.equals(rhs));
120     }
121 
122     /**
123      * <p>
124      * Constructs a builder for the specified objects with the specified style.
125      * </p>
126      * 
127      * <p>
128      * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will
129      * not evaluate any calls to {@code append(...)} and will return an empty
130      * {@link DiffResult} when {@link #build()} is executed.
131      * </p>
132      * 
133      * <p>
134      * This delegates to {@link #DiffBuilder(Object, Object, ToStringStyle, boolean)}
135      * with the testTriviallyEqual flag enabled.
136      * </p>
137      *
138      * @param lhs
139      *            {@code this} object
140      * @param rhs
141      *            the object to diff against
142      * @param style
143      *            the style will use when outputting the objects, {@code null}
144      *            uses the default
145      * @throws IllegalArgumentException
146      *             if {@code lhs} or {@code rhs} is {@code null}
147      */
148     public DiffBuilder(final Object lhs, final Object rhs,
149             final ToStringStyle style) {
150 
151             this(lhs, rhs, style, true);
152     }
153 
154     /**
155      * <p>
156      * Test if two {@code boolean}s are equal.
157      * </p>
158      * 
159      * @param fieldName
160      *            the field name
161      * @param lhs
162      *            the left hand {@code boolean}
163      * @param rhs
164      *            the right hand {@code boolean}
165      * @return this
166      * @throws IllegalArgumentException
167      *             if field name is {@code null}
168      */
169     public DiffBuilder append(final String fieldName, final boolean lhs,
170             final boolean rhs) {
171         if (fieldName == null) {
172             throw new IllegalArgumentException("Field name cannot be null");
173         }
174 
175         if (objectsTriviallyEqual) {
176             return this;
177         }
178         if (lhs != rhs) {
179             diffs.add(new Diff<Boolean>(fieldName) {
180                 private static final long serialVersionUID = 1L;
181 
182                 @Override
183                 public Boolean getLeft() {
184                     return Boolean.valueOf(lhs);
185                 }
186 
187                 @Override
188                 public Boolean getRight() {
189                     return Boolean.valueOf(rhs);
190                 }
191             });
192         }
193         return this;
194     }
195 
196     /**
197      * <p>
198      * Test if two {@code boolean[]}s are equal.
199      * </p>
200      * 
201      * @param fieldName
202      *            the field name
203      * @param lhs
204      *            the left hand {@code boolean[]}
205      * @param rhs
206      *            the right hand {@code boolean[]}
207      * @return this
208      * @throws IllegalArgumentException
209      *             if field name is {@code null}
210      */
211     public DiffBuilder append(final String fieldName, final boolean[] lhs,
212             final boolean[] rhs) {
213         if (fieldName == null) {
214             throw new IllegalArgumentException("Field name cannot be null");
215         }
216         if (objectsTriviallyEqual) {
217             return this;
218         }
219         if (!Arrays.equals(lhs, rhs)) {
220             diffs.add(new Diff<Boolean[]>(fieldName) {
221                 private static final long serialVersionUID = 1L;
222 
223                 @Override
224                 public Boolean[] getLeft() {
225                     return ArrayUtils.toObject(lhs);
226                 }
227 
228                 @Override
229                 public Boolean[] getRight() {
230                     return ArrayUtils.toObject(rhs);
231                 }
232             });
233         }
234         return this;
235     }
236 
237     /**
238      * <p>
239      * Test if two {@code byte}s are equal.
240      * </p>
241      * 
242      * @param fieldName
243      *            the field name
244      * @param lhs
245      *            the left hand {@code byte}
246      * @param rhs
247      *            the right hand {@code byte}
248      * @return this
249      * @throws IllegalArgumentException
250      *             if field name is {@code null}
251      */
252     public DiffBuilder append(final String fieldName, final byte lhs,
253             final byte rhs) {
254         if (fieldName == null) {
255             throw new IllegalArgumentException("Field name cannot be null");
256         }
257         if (objectsTriviallyEqual) {
258             return this;
259         }
260         if (lhs != rhs) {
261             diffs.add(new Diff<Byte>(fieldName) {
262                 private static final long serialVersionUID = 1L;
263 
264                 @Override
265                 public Byte getLeft() {
266                     return Byte.valueOf(lhs);
267                 }
268 
269                 @Override
270                 public Byte getRight() {
271                     return Byte.valueOf(rhs);
272                 }
273             });
274         }
275         return this;
276     }
277 
278     /**
279      * <p>
280      * Test if two {@code byte[]}s are equal.
281      * </p>
282      * 
283      * @param fieldName
284      *            the field name
285      * @param lhs
286      *            the left hand {@code byte[]}
287      * @param rhs
288      *            the right hand {@code byte[]}
289      * @return this
290      * @throws IllegalArgumentException
291      *             if field name is {@code null}
292      */
293     public DiffBuilder append(final String fieldName, final byte[] lhs,
294             final byte[] rhs) {
295         if (fieldName == null) {
296             throw new IllegalArgumentException("Field name cannot be null");
297         }
298 
299         if (objectsTriviallyEqual) {
300             return this;
301         }
302         if (!Arrays.equals(lhs, rhs)) {
303             diffs.add(new Diff<Byte[]>(fieldName) {
304                 private static final long serialVersionUID = 1L;
305 
306                 @Override
307                 public Byte[] getLeft() {
308                     return ArrayUtils.toObject(lhs);
309                 }
310 
311                 @Override
312                 public Byte[] getRight() {
313                     return ArrayUtils.toObject(rhs);
314                 }
315             });
316         }
317         return this;
318     }
319 
320     /**
321      * <p>
322      * Test if two {@code char}s are equal.
323      * </p>
324      * 
325      * @param fieldName
326      *            the field name
327      * @param lhs
328      *            the left hand {@code char}
329      * @param rhs
330      *            the right hand {@code char}
331      * @return this
332      * @throws IllegalArgumentException
333      *             if field name is {@code null}
334      */
335     public DiffBuilder append(final String fieldName, final char lhs,
336             final char rhs) {
337         if (fieldName == null) {
338             throw new IllegalArgumentException("Field name cannot be null");
339         }
340 
341         if (objectsTriviallyEqual) {
342             return this;
343         }
344         if (lhs != rhs) {
345             diffs.add(new Diff<Character>(fieldName) {
346                 private static final long serialVersionUID = 1L;
347 
348                 @Override
349                 public Character getLeft() {
350                     return Character.valueOf(lhs);
351                 }
352 
353                 @Override
354                 public Character getRight() {
355                     return Character.valueOf(rhs);
356                 }
357             });
358         }
359         return this;
360     }
361 
362     /**
363      * <p>
364      * Test if two {@code char[]}s are equal.
365      * </p>
366      * 
367      * @param fieldName
368      *            the field name
369      * @param lhs
370      *            the left hand {@code char[]}
371      * @param rhs
372      *            the right hand {@code char[]}
373      * @return this
374      * @throws IllegalArgumentException
375      *             if field name is {@code null}
376      */
377     public DiffBuilder append(final String fieldName, final char[] lhs,
378             final char[] rhs) {
379         if (fieldName == null) {
380             throw new IllegalArgumentException("Field name cannot be null");
381         }
382 
383         if (objectsTriviallyEqual) {
384             return this;
385         }
386         if (!Arrays.equals(lhs, rhs)) {
387             diffs.add(new Diff<Character[]>(fieldName) {
388                 private static final long serialVersionUID = 1L;
389 
390                 @Override
391                 public Character[] getLeft() {
392                     return ArrayUtils.toObject(lhs);
393                 }
394 
395                 @Override
396                 public Character[] getRight() {
397                     return ArrayUtils.toObject(rhs);
398                 }
399             });
400         }
401         return this;
402     }
403 
404     /**
405      * <p>
406      * Test if two {@code double}s are equal.
407      * </p>
408      * 
409      * @param fieldName
410      *            the field name
411      * @param lhs
412      *            the left hand {@code double}
413      * @param rhs
414      *            the right hand {@code double}
415      * @return this
416      * @throws IllegalArgumentException
417      *             if field name is {@code null}
418      */
419     public DiffBuilder append(final String fieldName, final double lhs,
420             final double rhs) {
421         if (fieldName == null) {
422             throw new IllegalArgumentException("Field name cannot be null");
423         }
424 
425         if (objectsTriviallyEqual) {
426             return this;
427         }
428         if (Double.doubleToLongBits(lhs) != Double.doubleToLongBits(rhs)) {
429             diffs.add(new Diff<Double>(fieldName) {
430                 private static final long serialVersionUID = 1L;
431 
432                 @Override
433                 public Double getLeft() {
434                     return Double.valueOf(lhs);
435                 }
436 
437                 @Override
438                 public Double getRight() {
439                     return Double.valueOf(rhs);
440                 }
441             });
442         }
443         return this;
444     }
445 
446     /**
447      * <p>
448      * Test if two {@code double[]}s are equal.
449      * </p>
450      * 
451      * @param fieldName
452      *            the field name
453      * @param lhs
454      *            the left hand {@code double[]}
455      * @param rhs
456      *            the right hand {@code double[]}
457      * @return this
458      * @throws IllegalArgumentException
459      *             if field name is {@code null}
460      */
461     public DiffBuilder append(final String fieldName, final double[] lhs,
462             final double[] rhs) {
463         if (fieldName == null) {
464             throw new IllegalArgumentException("Field name cannot be null");
465         }
466 
467         if (objectsTriviallyEqual) {
468             return this;
469         }
470         if (!Arrays.equals(lhs, rhs)) {
471             diffs.add(new Diff<Double[]>(fieldName) {
472                 private static final long serialVersionUID = 1L;
473 
474                 @Override
475                 public Double[] getLeft() {
476                     return ArrayUtils.toObject(lhs);
477                 }
478 
479                 @Override
480                 public Double[] getRight() {
481                     return ArrayUtils.toObject(rhs);
482                 }
483             });
484         }
485         return this;
486     }
487 
488     /**
489      * <p>
490      * Test if two {@code float}s are equal.
491      * </p>
492      * 
493      * @param fieldName
494      *            the field name
495      * @param lhs
496      *            the left hand {@code float}
497      * @param rhs
498      *            the right hand {@code float}
499      * @return this
500      * @throws IllegalArgumentException
501      *             if field name is {@code null}
502      */
503     public DiffBuilder append(final String fieldName, final float lhs,
504             final float rhs) {
505         if (fieldName == null) {
506             throw new IllegalArgumentException("Field name cannot be null");
507         }
508 
509         if (objectsTriviallyEqual) {
510             return this;
511         }
512         if (Float.floatToIntBits(lhs) != Float.floatToIntBits(rhs)) {
513             diffs.add(new Diff<Float>(fieldName) {
514                 private static final long serialVersionUID = 1L;
515 
516                 @Override
517                 public Float getLeft() {
518                     return Float.valueOf(lhs);
519                 }
520 
521                 @Override
522                 public Float getRight() {
523                     return Float.valueOf(rhs);
524                 }
525             });
526         }
527         return this;
528     }
529 
530     /**
531      * <p>
532      * Test if two {@code float[]}s are equal.
533      * </p>
534      * 
535      * @param fieldName
536      *            the field name
537      * @param lhs
538      *            the left hand {@code float[]}
539      * @param rhs
540      *            the right hand {@code float[]}
541      * @return this
542      * @throws IllegalArgumentException
543      *             if field name is {@code null}
544      */
545     public DiffBuilder append(final String fieldName, final float[] lhs,
546             final float[] rhs) {
547         if (fieldName == null) {
548             throw new IllegalArgumentException("Field name cannot be null");
549         }
550 
551         if (objectsTriviallyEqual) {
552             return this;
553         }
554         if (!Arrays.equals(lhs, rhs)) {
555             diffs.add(new Diff<Float[]>(fieldName) {
556                 private static final long serialVersionUID = 1L;
557 
558                 @Override
559                 public Float[] getLeft() {
560                     return ArrayUtils.toObject(lhs);
561                 }
562 
563                 @Override
564                 public Float[] getRight() {
565                     return ArrayUtils.toObject(rhs);
566                 }
567             });
568         }
569         return this;
570     }
571 
572     /**
573      * <p>
574      * Test if two {@code int}s are equal.
575      * </p>
576      * 
577      * @param fieldName
578      *            the field name
579      * @param lhs
580      *            the left hand {@code int}
581      * @param rhs
582      *            the right hand {@code int}
583      * @return this
584      * @throws IllegalArgumentException
585      *             if field name is {@code null}
586      */
587     public DiffBuilder append(final String fieldName, final int lhs,
588             final int rhs) {
589         if (fieldName == null) {
590             throw new IllegalArgumentException("Field name cannot be null");
591         }
592 
593         if (objectsTriviallyEqual) {
594             return this;
595         }
596         if (lhs != rhs) {
597             diffs.add(new Diff<Integer>(fieldName) {
598                 private static final long serialVersionUID = 1L;
599 
600                 @Override
601                 public Integer getLeft() {
602                     return Integer.valueOf(lhs);
603                 }
604 
605                 @Override
606                 public Integer getRight() {
607                     return Integer.valueOf(rhs);
608                 }
609             });
610         }
611         return this;
612     }
613 
614     /**
615      * <p>
616      * Test if two {@code int[]}s are equal.
617      * </p>
618      * 
619      * @param fieldName
620      *            the field name
621      * @param lhs
622      *            the left hand {@code int[]}
623      * @param rhs
624      *            the right hand {@code int[]}
625      * @return this
626      * @throws IllegalArgumentException
627      *             if field name is {@code null}
628      */
629     public DiffBuilder append(final String fieldName, final int[] lhs,
630             final int[] rhs) {
631         if (fieldName == null) {
632             throw new IllegalArgumentException("Field name cannot be null");
633         }
634 
635         if (objectsTriviallyEqual) {
636             return this;
637         }
638         if (!Arrays.equals(lhs, rhs)) {
639             diffs.add(new Diff<Integer[]>(fieldName) {
640                 private static final long serialVersionUID = 1L;
641 
642                 @Override
643                 public Integer[] getLeft() {
644                     return ArrayUtils.toObject(lhs);
645                 }
646 
647                 @Override
648                 public Integer[] getRight() {
649                     return ArrayUtils.toObject(rhs);
650                 }
651             });
652         }
653         return this;
654     }
655 
656     /**
657      * <p>
658      * Test if two {@code long}s are equal.
659      * </p>
660      * 
661      * @param fieldName
662      *            the field name
663      * @param lhs
664      *            the left hand {@code long}
665      * @param rhs
666      *            the right hand {@code long}
667      * @return this
668      * @throws IllegalArgumentException
669      *             if field name is {@code null}
670      */
671     public DiffBuilder append(final String fieldName, final long lhs,
672             final long rhs) {
673         if (fieldName == null) {
674             throw new IllegalArgumentException("Field name cannot be null");
675         }
676 
677         if (objectsTriviallyEqual) {
678             return this;
679         }
680         if (lhs != rhs) {
681             diffs.add(new Diff<Long>(fieldName) {
682                 private static final long serialVersionUID = 1L;
683 
684                 @Override
685                 public Long getLeft() {
686                     return Long.valueOf(lhs);
687                 }
688 
689                 @Override
690                 public Long getRight() {
691                     return Long.valueOf(rhs);
692                 }
693             });
694         }
695         return this;
696     }
697 
698     /**
699      * <p>
700      * Test if two {@code long[]}s are equal.
701      * </p>
702      * 
703      * @param fieldName
704      *            the field name
705      * @param lhs
706      *            the left hand {@code long[]}
707      * @param rhs
708      *            the right hand {@code long[]}
709      * @return this
710      * @throws IllegalArgumentException
711      *             if field name is {@code null}
712      */
713     public DiffBuilder append(final String fieldName, final long[] lhs,
714             final long[] rhs) {
715         if (fieldName == null) {
716             throw new IllegalArgumentException("Field name cannot be null");
717         }
718 
719         if (objectsTriviallyEqual) {
720             return this;
721         }
722         if (!Arrays.equals(lhs, rhs)) {
723             diffs.add(new Diff<Long[]>(fieldName) {
724                 private static final long serialVersionUID = 1L;
725 
726                 @Override
727                 public Long[] getLeft() {
728                     return ArrayUtils.toObject(lhs);
729                 }
730 
731                 @Override
732                 public Long[] getRight() {
733                     return ArrayUtils.toObject(rhs);
734                 }
735             });
736         }
737         return this;
738     }
739 
740     /**
741      * <p>
742      * Test if two {@code short}s are equal.
743      * </p>
744      * 
745      * @param fieldName
746      *            the field name
747      * @param lhs
748      *            the left hand {@code short}
749      * @param rhs
750      *            the right hand {@code short}
751      * @return this
752      * @throws IllegalArgumentException
753      *             if field name is {@code null}
754      */
755     public DiffBuilder append(final String fieldName, final short lhs,
756             final short rhs) {
757         if (fieldName == null) {
758             throw new IllegalArgumentException("Field name cannot be null");
759         }
760 
761         if (objectsTriviallyEqual) {
762             return this;
763         }
764         if (lhs != rhs) {
765             diffs.add(new Diff<Short>(fieldName) {
766                 private static final long serialVersionUID = 1L;
767 
768                 @Override
769                 public Short getLeft() {
770                     return Short.valueOf(lhs);
771                 }
772 
773                 @Override
774                 public Short getRight() {
775                     return Short.valueOf(rhs);
776                 }
777             });
778         }
779         return this;
780     }
781 
782     /**
783      * <p>
784      * Test if two {@code short[]}s are equal.
785      * </p>
786      * 
787      * @param fieldName
788      *            the field name
789      * @param lhs
790      *            the left hand {@code short[]}
791      * @param rhs
792      *            the right hand {@code short[]}
793      * @return this
794      * @throws IllegalArgumentException
795      *             if field name is {@code null}
796      */
797     public DiffBuilder append(final String fieldName, final short[] lhs,
798             final short[] rhs) {
799         if (fieldName == null) {
800             throw new IllegalArgumentException("Field name cannot be null");
801         }
802 
803         if (objectsTriviallyEqual) {
804             return this;
805         }
806         if (!Arrays.equals(lhs, rhs)) {
807             diffs.add(new Diff<Short[]>(fieldName) {
808                 private static final long serialVersionUID = 1L;
809 
810                 @Override
811                 public Short[] getLeft() {
812                     return ArrayUtils.toObject(lhs);
813                 }
814 
815                 @Override
816                 public Short[] getRight() {
817                     return ArrayUtils.toObject(rhs);
818                 }
819             });
820         }
821         return this;
822     }
823 
824     /**
825      * <p>
826      * Test if two {@code Objects}s are equal.
827      * </p>
828      * 
829      * @param fieldName
830      *            the field name
831      * @param lhs
832      *            the left hand {@code Object}
833      * @param rhs
834      *            the right hand {@code Object}
835      * @return this
836      */
837     public DiffBuilder append(final String fieldName, final Object lhs,
838             final Object rhs) {
839 
840         if (objectsTriviallyEqual) {
841             return this;
842         }
843         if (lhs == rhs) {
844             return this;
845         }
846 
847         Object objectToTest;
848         if (lhs != null) {
849             objectToTest = lhs;
850         } else {
851             // rhs cannot be null, as lhs != rhs
852             objectToTest = rhs;
853         }
854 
855         if (objectToTest.getClass().isArray()) {
856             if (objectToTest instanceof boolean[]) {
857                 return append(fieldName, (boolean[]) lhs, (boolean[]) rhs);
858             }
859             if (objectToTest instanceof byte[]) {
860                 return append(fieldName, (byte[]) lhs, (byte[]) rhs);
861             }
862             if (objectToTest instanceof char[]) {
863                 return append(fieldName, (char[]) lhs, (char[]) rhs);
864             }
865             if (objectToTest instanceof double[]) {
866                 return append(fieldName, (double[]) lhs, (double[]) rhs);
867             }
868             if (objectToTest instanceof float[]) {
869                 return append(fieldName, (float[]) lhs, (float[]) rhs);
870             }
871             if (objectToTest instanceof int[]) {
872                 return append(fieldName, (int[]) lhs, (int[]) rhs);
873             }
874             if (objectToTest instanceof long[]) {
875                 return append(fieldName, (long[]) lhs, (long[]) rhs);
876             }
877             if (objectToTest instanceof short[]) {
878                 return append(fieldName, (short[]) lhs, (short[]) rhs);
879             }
880 
881             return append(fieldName, (Object[]) lhs, (Object[]) rhs);
882         }
883 
884         // Not array type
885         if (lhs != null && lhs.equals(rhs)) {
886             return this;
887         }
888 
889         diffs.add(new Diff<Object>(fieldName) {
890             private static final long serialVersionUID = 1L;
891 
892             @Override
893             public Object getLeft() {
894                 return lhs;
895             }
896 
897             @Override
898             public Object getRight() {
899                 return rhs;
900             }
901         });
902 
903         return this;
904     }
905 
906     /**
907      * <p>
908      * Test if two {@code Object[]}s are equal.
909      * </p>
910      * 
911      * @param fieldName
912      *            the field name
913      * @param lhs
914      *            the left hand {@code Object[]}
915      * @param rhs
916      *            the right hand {@code Object[]}
917      * @return this
918      */
919     public DiffBuilder append(final String fieldName, final Object[] lhs,
920             final Object[] rhs) {
921         if (objectsTriviallyEqual) {
922             return this;
923         }
924 
925         if (!Arrays.equals(lhs, rhs)) {
926             diffs.add(new Diff<Object[]>(fieldName) {
927                 private static final long serialVersionUID = 1L;
928 
929                 @Override
930                 public Object[] getLeft() {
931                     return lhs;
932                 }
933 
934                 @Override
935                 public Object[] getRight() {
936                     return rhs;
937                 }
938             });
939         }
940 
941         return this;
942     }
943 
944     /**
945      * <p>
946      * Builds a {@link DiffResult} based on the differences appended to this
947      * builder.
948      * </p>
949      * 
950      * @return a {@code DiffResult} containing the differences between the two
951      *         objects.
952      */
953     @Override
954     public DiffResult build() {
955         return new DiffResult(left, right, diffs, style);
956     }
957 
958 }